package com.itzhanghada.rebitmq.redis;

import com.itzhanghada.rebitmq.domin.vo.TransactionRecord;
import com.itzhanghada.rebitmq.enums.TransactionStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@Component
public class RedisStorageService {
    private static final String TX_PREFIX = "rebit:tx:";
    private static final String COMPENSATION_SET = "rebit:tx:compensation_set";
    private static final String CONSUMED_PREFIX = "rebit:consumed:";
    
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    // 保存事务记录
    public void saveTransactionRecord(TransactionRecord record) {
        String key = TX_PREFIX + record.getTxId();
        Map<String, Object> map = new HashMap<>();
        map.put("txId", record.getTxId());
        map.put("status", record.getStatus().name());
        map.put("createTime", record.getCreateTime());
        map.put("updateTime", record.getUpdateTime());
        map.put("retryCount", record.getRetryCount());
        map.put("maxRetry", record.getMaxRetry());
        map.put("exchange", record.getExchange());
        map.put("routingKey", record.getRoutingKey());
        map.put("body", record.getBody());
        map.put("serviceName", record.getServiceName());
        map.put("className", record.getClassName());
        map.put("methodName", record.getMethodName());
        
        redisTemplate.opsForHash().putAll(key, map);
        
        // 添加到补偿集合
        if (record.getStatus() == TransactionStatus.PREPARED ||
            record.getStatus() == TransactionStatus.RETRYING) {
            redisTemplate.opsForZSet().add(COMPENSATION_SET, record.getTxId(), record.getCreateTime());
        }
    }
    
    // 更新事务状态
    public void updateTransactionStatus(String txId, TransactionStatus status) {
        String key = TX_PREFIX + txId;
        redisTemplate.opsForHash().put(key, "status", status.name());
        redisTemplate.opsForHash().put(key, "updateTime", System.currentTimeMillis());
        
        if (status == TransactionStatus.SENT || status == TransactionStatus.CONSUMED) {
            // 从补偿集合中移除
            redisTemplate.opsForZSet().remove(COMPENSATION_SET, txId);
        } else if (status == TransactionStatus.RETRYING) {
            // 添加到补偿集合
            redisTemplate.opsForZSet().add(COMPENSATION_SET, txId, System.currentTimeMillis());
        }
    }
    
    // 获取事务记录
    public TransactionRecord getTransactionRecord(String txId) {
        String key = TX_PREFIX + txId;
        Map<Object, Object> map = redisTemplate.opsForHash().entries(key);
        if (map.isEmpty()) {
            return null;
        }
        
        TransactionRecord record = new TransactionRecord();
        record.setTxId((String) map.get("txId"));
        record.setStatus(TransactionStatus.valueOf((String) map.get("status")));
        record.setCreateTime(Long.parseLong(map.get("createTime").toString()));
        record.setUpdateTime(Long.parseLong(map.get("updateTime").toString()));
        record.setRetryCount(Integer.parseInt(map.get("retryCount").toString()));
        record.setMaxRetry(Integer.parseInt(map.get("maxRetry").toString()));
        record.setExchange((String) map.get("exchange"));
        record.setRoutingKey((String) map.get("routingKey"));
        record.setBody((String) map.get("body"));
        record.setServiceName((String) map.get("serviceName"));
        record.setClassName((String) map.get("className"));
        record.setMethodName((String) map.get("methodName"));
        
        return record;
    }
    
    // 标记消息已消费（幂等性控制）
    public boolean markMessageConsumed(String txId, String serviceId) {
        String key = CONSUMED_PREFIX + txId + ":" + serviceId;
        return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, "1", Duration.ofHours(24)));
    }
    
    // 获取需要补偿的事务ID列表
    public Set<String> getCompensationTxIds(long timeoutMillis) {
        long maxScore = System.currentTimeMillis() - timeoutMillis;
        return redisTemplate.opsForZSet().rangeByScore(COMPENSATION_SET, 0, maxScore);
    }
}